package org.boulderfoodrescue.webapp.server.location;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;

import org.boulderfoodrescue.webapp.shared.Location;
import org.boulderfoodrescue.webapp.shared.Location.LocationType;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;

public class LocationDatabase {
	private static final Logger log = Logger.getLogger(LocationDatabase.class.getName());

	public static Location addLocation(Location location){
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Entity databaseLocation = locationToEntity(location);
		Long key = datastore.put(databaseLocation).getId();
		location.setDatabaseKey(key);
		log.info("Added New Location to Database: "+location.getName());
		return location;
	}
	
	public static Location getLocation(Long databaseKey, Boolean isDonor){
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Key key = KeyFactory.createKey("location", databaseKey);
		Entity entity;
		try {
			entity = datastore.get(key);
		} catch (EntityNotFoundException e) {
			log.warning("Location was not found in the database");
			System.out.println("not found in database:"+databaseKey);
			return null;
		}
		Location location = entityToLocation(entity);
		return location;
	}
	
	public static List<Location> getDonors(){ 
		List<Location> donors = new LinkedList<Location>();
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Query query = new Query("location");
		query.addFilter("type", FilterOperator.EQUAL, 0l);
		List<Entity> dUsers = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(1000));
		if(dUsers.size() == 1000)
		{
			log.warning("There are at least 1000 donors in the database. This function will only return the first 1000 donors.");
		}
		for(Entity dUser:dUsers){
			Location user = entityToLocation(dUser);
			donors.add(user);
		}
		log.info("Retrieved user info for "+donors.size()+" donors.");
		return donors;
	}

	public static List<Location> getRecipients(){
		List<Location> recipients = new LinkedList<Location>();
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Query query = new Query("location");
		query.addFilter("type", FilterOperator.EQUAL, 1l);
		List<Entity> dUsers = datastore.prepare(query).asList(FetchOptions.Builder.withLimit(1000));
		if(dUsers.size() == 1000)
		{
			log.warning("There are at least 1000 recipients in the database. This function will only return the first 1000 donors.");
		}
		for(Entity dUser:dUsers){
			Location user = entityToLocation(dUser);
			recipients.add(user);
		}
		log.info("Retrieved user info for "+recipients.size()+" donors.");
		return recipients;
	}

	public static Long updateLocation(Location location){
		Long key = null;
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		key =  datastore.put(locationToEntity(location)).getId();
		log.info("Updated info for donor: " + location.getName());
		return key;
	}


	public static boolean removeLocation(Location location){
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Entity databaseDonor = new Entity("location", location.getDatabaseKey());
		datastore.delete(databaseDonor.getKey());
		log.info("Deleted donor: "+location.getName());
		return true;
	}

	private static Location entityToLocation(Entity dUser)
	{
		Location location;
		Long type = (Long) dUser.getProperty("type");
		if(type == null)
		{
			log.severe("Location type is null");
			return null;
		}
		switch(((Long)dUser.getProperty("type")).intValue())
		{
		case 0: location = new Location(LocationType.Donor);
		break;
		case 1: location = new Location(LocationType.Recipient);
		break;
		default: 
			log.severe("Uknown location type found in database");
			return null;
		}
		location.setAmmountExpected((Double) dUser.getProperty("ammountExpected"));
		location.setCity((String) dUser.getProperty("city"));
		location.setContactEmail((String) dUser.getProperty("contactEmail"));
		location.setContactName((String) dUser.getProperty("contactName"));
		location.setContactPhone((String) dUser.getProperty("contactPhone"));
		location.setCreatorEmail((String) dUser.getProperty("creatorEmail"));
		location.setDatabaseKey(dUser.getKey().getId());
		location.setFoodTypeFromInt((Long) dUser.getProperty("foodType"));
		location.setLatitude((Double) dUser.getProperty("latitude"));
		location.setLongitude((Double) dUser.getProperty("longitude"));
		location.setName((String) dUser.getProperty("name"));
		location.setNotes((String) dUser.getProperty("notes"));
		location.setState((String) dUser.getProperty("state"));
		location.setStreetAddress((String) dUser.getProperty("streetAddress"));
		location.setZipCode((String) dUser.getProperty("zipCode"));
		return location;
	}

	private static Entity locationToEntity(Location location)
	{
		Entity databaseLocation;
		if(location.getDatabaseKey() != null && location.getDatabaseKey() != 0)
			databaseLocation = new Entity("location", location.getDatabaseKey());
		else
			databaseLocation = new Entity("location");
		databaseLocation.setProperty("type", location.getTypeAsLong());
		databaseLocation.setProperty("ammountExpected", location.getAmmountExpected());
		databaseLocation.setProperty("city", location.getCity());
		databaseLocation.setProperty("contactEmail", location.getContactEmail());
		databaseLocation.setProperty("contactName", location.getContactName());
		databaseLocation.setProperty("contactPhone", location.getContactPhone());
		databaseLocation.setProperty("creatorEmail", location.getCreatorEmail());
		databaseLocation.setProperty("foodType", location.getFoodTypeAsInt());
		databaseLocation.setProperty("latitude", location.getLatitude());
		databaseLocation.setProperty("longitude", location.getLongitude());
		databaseLocation.setProperty("name", location.getName());
		databaseLocation.setProperty("notes", location.getNotes());
		databaseLocation.setProperty("state", location.getState());
		databaseLocation.setProperty("streetAddress", location.getStreetAddress());
		databaseLocation.setProperty("zipCode", location.getZipCode());
		return databaseLocation;
	}
}
